home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.001 / crossfir~ / eutl / chain-hash / chain-hash.c next >
C/C++ Source or Header  |  1994-09-19  |  5KB  |  194 lines

  1. #include <stdio.h>
  2.  
  3. #include <chain-hash.h>
  4. #include <xmalloc.h>
  5. #include <libc.h>
  6. extern HashFunction __eutl_default_hash;
  7.  
  8. static ErrorFunction Erf = LongJmpErrorFunction;
  9.  
  10. char *chainhash_packagever = "Chain Hashing V1.0";
  11. char *chainhash_Ebadinsert = "Bad Insertion";
  12. char *chainhash_Ebadlookup = "Bad Lookup";
  13.  
  14. /* Save the malloc overhead of having to malloc space for the
  15.    key and the data -- yea, probably a minor optimization */
  16.  
  17. typedef struct __Bucket {
  18.   xint keylen,datalen;
  19.   struct __Bucket *next;
  20.   unsigned char stuff[1];
  21. } Bucket;
  22.  
  23. /* PAD8 computes the number of bytes needed to round the value up to the 
  24.    next multiple of 8 */
  25. /*
  26. #define PAD8(bytes) ((8 - ((unsigned int) (bytes) %8)) % 8)
  27. */
  28. #define PAD8(bytes) ((8 - ((unsigned int) (bytes) & 0x7)) & 0x7)
  29. #define KEYOFBUCKET(b) ((b)->stuff)
  30. #define DATAOFBUCKET(b) ((b)->stuff + (b)->keylen + PAD8((b)->keylen))
  31. #define BUCKETMALLOCSIZE(klen,dlen) \
  32.    (sizeof(Bucket) + (klen) + PAD8(klen) + (dlen) - 1)
  33.  
  34. struct __chain_hash {
  35.   Bucket **buckets;
  36.   HashFunction hfunc;
  37.   UM32B nbuckets;
  38.   HashStatistics stats;
  39. };
  40.  
  41. static UM32B prime_list[] = {
  42.   97, 191, 433, 821, 1543, 3313, 6091, 12289, 24281, 48397, 100169,
  43.   213397, 487651, 882491, 1179589, 2471093 
  44. };
  45.  
  46. #define NPRIMES (sizeof(prime_list)/sizeof(UM32B))
  47.  
  48. HashTable CreateHashTable(long tablesize,HashFunction hfunc)
  49. {
  50.   HashTable ret;
  51.  
  52.   if (hfunc == NULL)
  53.     hfunc = __eutl_default_hash;
  54.   if (tablesize<=0) {
  55.     int l;
  56.     
  57.     tablesize = (- tablesize);
  58.  
  59.     for(l=0;l<NPRIMES;l++) {
  60.       if (prime_list[l] > tablesize)
  61.     break;
  62.     }
  63.     if (l==NPRIMES)
  64.       l = NPRIMES-1;
  65.     tablesize = prime_list[l];
  66.   }
  67.   ret = (HashTable)xbzmalloc(sizeof(struct __chain_hash));
  68.   ret->buckets = (Bucket **)xbzmalloc(sizeof(Bucket *)*tablesize);
  69.   ret->stats.nbuckets = tablesize;
  70.   ret->nbuckets = tablesize;
  71.   ret->hfunc = hfunc;
  72.  
  73.   return ret;
  74. }
  75.  
  76. void DestroyHashTable(HashTable table,DestroyBucketFunc func)
  77. {
  78.   xint l;
  79.   Bucket *j,*nextj;
  80.  
  81.   if (func != NULL) {
  82.     for(l=0;l<table->nbuckets;l++) {
  83.       for(j=table->buckets[l];j != NULL;j=nextj) {
  84.     nextj = j->next;
  85.     func(KEYOFBUCKET(j),j->keylen,DATAOFBUCKET(j),j->datalen);
  86.     free(j);
  87.       }
  88.     }
  89.   } else {
  90.     for(l=0;l<table->nbuckets;l++) {
  91.       for(j=table->buckets[l];j != NULL;j=nextj) {
  92.     nextj = j->next;
  93.     free(j);
  94.       }
  95.     }
  96.   }
  97. }
  98.  
  99. void HashInsert(HashTable table,void *key,xint keylen,void *data,xint datalen)
  100. {
  101.   UM32B hval = table->hfunc(key,keylen) % table->nbuckets;
  102.   Bucket *newbucket;
  103.  
  104.   for(newbucket=table->buckets[hval]; 
  105.       newbucket != NULL; 
  106.       newbucket = newbucket->next) {
  107.     if ((keylen == newbucket->keylen) && 
  108.     (bcmp(KEYOFBUCKET(newbucket),key,keylen)==0)) {
  109.       Erf(chainhash_packagever,chainhash_Ebadinsert,
  110.       "Hash entry already exists with specified key.");
  111.     }
  112.   }
  113.   table->stats.nentries++;
  114.   newbucket = (Bucket *)xmalloc(BUCKETMALLOCSIZE(keylen,datalen));
  115.   newbucket->keylen = keylen;
  116.   newbucket->datalen = datalen;
  117.   bcopy(key,KEYOFBUCKET(newbucket),keylen);
  118.   bcopy(data,DATAOFBUCKET(newbucket),datalen);
  119.   if (table->buckets[hval] == NULL) {
  120.     table->stats.bucketsused++;
  121.   }
  122.   newbucket->next = table->buckets[hval];
  123.   table->buckets[hval] = newbucket;
  124. }
  125.  
  126. void SHashInsert(HashTable table,char *key,void *data,xint datalen)
  127. {
  128.   HashInsert(table,key,strlen(key)+1,data,datalen);
  129. }
  130.  
  131. void HashOverwrite(HashTable table,void *key,xint keylen,void *data,xint datalen)
  132. {
  133.   UM32B hval = table->hfunc(key,keylen) % table->nbuckets;
  134.   Bucket *oldbucket;
  135.  
  136.   for(oldbucket=table->buckets[hval]; 
  137.       oldbucket != NULL; 
  138.       oldbucket = oldbucket->next) {
  139.     if ((keylen == oldbucket->keylen) && 
  140.     (bcmp(KEYOFBUCKET(oldbucket),key,keylen)==0)) {
  141.       break;
  142.     }
  143.   }
  144.   if (oldbucket == NULL) {
  145.     /* read oldbucket in this part of the if as newbucket */
  146.     table->stats.nentries++;
  147.     oldbucket = (Bucket *)xmalloc(BUCKETMALLOCSIZE(keylen,datalen));
  148.     oldbucket->keylen = keylen;
  149.     oldbucket->datalen = datalen;
  150.     bcopy(key,KEYOFBUCKET(oldbucket),keylen);
  151.     bcopy(data,DATAOFBUCKET(oldbucket),datalen);
  152.     if (table->buckets[hval] == NULL) {
  153.       table->stats.bucketsused++;
  154.     }
  155.     oldbucket->next = table->buckets[hval];
  156.     table->buckets[hval] = oldbucket;
  157.   } else {
  158.     oldbucket = (Bucket *)xrealloc(oldbucket,BUCKETMALLOCSIZE(keylen,datalen));
  159.     oldbucket->datalen = datalen;
  160.     bcopy(data,DATAOFBUCKET(oldbucket),datalen);
  161.   }
  162. }
  163.  
  164. void SHashOverwrite(HashTable table,char *key,void *data,xint datalen)
  165. {
  166.   HashOverwrite(table,key,strlen(key)+1,data,datalen);
  167. }
  168.  
  169. void *HashLookup(HashTable table,void *key,xint keylen)
  170. {
  171.   UM32B hval = table->hfunc(key,keylen) % table->nbuckets;
  172.   Bucket *l;
  173.  
  174.   for(l=table->buckets[hval]; l != NULL; l = l->next) {
  175.     if ((keylen == l->keylen) && 
  176.     (bcmp(KEYOFBUCKET(l),key,keylen)==0)) {
  177.       return DATAOFBUCKET(l);
  178.     }
  179.   }
  180.   Erf(chainhash_packagever,chainhash_Ebadlookup,
  181.       "Hash entry with specified key doesn't exist.");
  182.   return NULL;
  183. }
  184.  
  185. void *SHashLookup(HashTable table,char *key)
  186. {
  187.   return HashLookup(table,key,strlen(key)+1);
  188. }
  189.  
  190. HashStatistics *GetStatistics(HashTable table)
  191. {
  192.   return &table->stats;
  193. }
  194.